import { nodePasteRule, PasteRuleMatch, VueRenderer } from "@tiptap/vue-3";
import tippy, { Instance, Props } from "tippy.js";
import MentionList from "./MentionList.vue";
import Mention from "@tiptap/extension-mention";
import { PluginKey } from "@tiptap/pm/state";

const getFunctionMention = (formulaList: any[]) => {
  const getformulaRegex = () => {
    const funcnames = formulaList.reduce<string[]>((pre, { label }) => {
      return pre.push(label), pre;
    }, []);
    return new RegExp(`@(${funcnames.join("|")})\\(`, "g");
  };

  const FunctionMention = Mention.extend({
    name: "function",
    deleteTriggerWithBackspace: false,
    priority: 1000,
    addAttributes() {
      return {
        ...this.parent?.(),
        class: {
          default: "formula-tag",
        },
      };
    },
    addPasteRules() {
      return [
        nodePasteRule({
          find(text) {
            const reg = getformulaRegex();
            const matchedArr: PasteRuleMatch[] = [];
            let currentMatched;
            while ((currentMatched = reg.exec(text)) !== null) {
              const value = currentMatched[1];
              matchedArr.push({
                index: currentMatched.index,
                text: `@${value}`,
                replaceWith: `${value} `,
                data: { label: currentMatched[1], id: currentMatched[1] },
              });
            }
            return matchedArr;
          },
          type: this.type,
          getAttributes(match) {
            return match.data!;
          },
        }),
      ];
    },
  });

  return FunctionMention.configure({
    suggestion: {
      char: "@",
      decorationClass: "char-tag",
      allowedPrefixes: null,
      pluginKey: new PluginKey("FunctionMention$"),
      items: ({ query }) => {
        return formulaList
          .filter(({ value }) =>
            value.toLowerCase().startsWith(query.toLowerCase())
          )
          .slice(0, 5);
      },

      command({ editor, props, range }) {
        const { label, value } = props as any;
        // 获取第一个括号后的位置
        editor.commands.insertContentAt(range, [
          {
            type: "function",
            attrs: {
              id: value,
              label: label,
            },
          },
          {
            type: "text",
            text: "()",
          },
        ]);
        editor.commands.setTextSelection(range.to + 1);
      },

      render: () => {
        let component: VueRenderer;
        let popup: Instance<Props>[];
        return {
          onStart: (props: any) => {
            component = new VueRenderer(MentionList, {
              // using vue 2:
              // parent: this,
              // propsData: props,
              props,
              editor: props.editor,
            });

            if (!props.clientRect) {
              return;
            }

            popup = tippy("body", {
              getReferenceClientRect: props.clientRect,
              appendTo: () => document.body,
              content: component.element!,
              showOnCreate: true,
              interactive: true,
              trigger: "manual",
              placement: "bottom-start",
            });
          },

          onUpdate(props: any) {
            component.updateProps(props);

            if (!props.clientRect) {
              return;
            }

            popup[0].setProps({
              getReferenceClientRect: props.clientRect,
            });
          },

          onKeyDown(props) {
            if (props.event.key === "Escape") {
              popup[0].hide();
              return true;
            }

            return component.ref?.onKeyDown(props);
          },

          onExit() {
            popup[0].destroy();
            component.destroy();
          },
        };
      },
    },
  });
};

export default getFunctionMention;
